﻿using Inaction.Criteria;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace Inaction.Linq.Clause
{
    abstract class WhereClause : IWhereClause
    {
        public readonly static EmptyClause Empty = new EmptyClause(null);
        public static string ParaFix
        {
            get { return Inaction.DbProvider.Instance.ParaFix; }
        }

        public LinqRoot Root { get; protected set; }

        internal Expression Express { get; private set; }

        #region IWhereClause
        public virtual bool IsValue
        {
            get { return false; }
        }
        public Type Type
        {
            get;
            protected set;
        }
        public IWhereClause Left
        {
            get;
            protected set;
        }

        public IWhereClause Right
        {
            get;
            protected set;
        }

        public virtual CriteriaLogic? Logic
        {
            get;
            protected set;
        }

        public virtual CriteriaOperate? Operate
        {
            get;
            protected set;
        }

        public Mapping.ParaValue ParaValue
        {
            get;
            protected set;
        }

        public virtual string GetClauseSql()
        {
            string s = string.Empty;
            if (Logic != null)
            {
                s = Rule.EnumDescription.GetDescription(Logic);
            }
            else if (Operate != null)
            {
                s = Rule.EnumDescription.GetDescription(Operate);
            }
            if (Left != null)
            {
                if (Logic != null)
                {
                    s = "(" + Left.GetClauseSql() + ")" + s;
                }
                else
                {
                    s = Left.GetClauseSql() + s;
                }
            }
            if (Right != null)
            {
                if (Logic != null)
                {
                    s = s + "(" + Right.GetClauseSql() + ")";
                }
                else
                {
                    s = s + Right.GetClauseSql();
                }
            }
            return s;
        }

        #endregion

        public WhereClause(LinqRoot root, Expression e)
        {
            Root = root;
            Express = e;
        }

        public static WhereClause operator &(WhereClause condition1, WhereClause condition2)
        {
            return GetConditionClause(condition1, condition2, new AndClause(condition1, condition2));
        }

        public WhereClause And(WhereClause condition2)
        {
            return GetConditionClause(this, condition2, new AndClause(this, condition2));
        }

        public static WhereClause operator |(WhereClause condition1, WhereClause condition2)
        {
            return GetConditionClause(condition1, condition2, new OrClause(condition1, condition2));
        }
        public WhereClause Or(WhereClause condition2)
        {
            return GetConditionClause(this, condition2, new OrClause(this, condition2));
        }

        private static WhereClause GetConditionClause(WhereClause condition1, WhereClause condition2, WhereClause notNullCondition)
        {
            if (IsNullOrEmpty(condition1) && IsNullOrEmpty(condition2))
            {
                return Empty;
            }
            if (!IsNullOrEmpty(condition1) && !IsNullOrEmpty(condition2))
            {
                return notNullCondition;
            }
            if (!IsNullOrEmpty(condition1))
            {
                return condition1;
            }
            return condition2;
        }

        public static bool IsNullOrEmpty(IWhereClause clause)
        {
            return (clause == null || (clause is EmptyClause));
        }

        public override string ToString()
        {
            if (Express != null)
                return Express.ToString();
            return GetClauseSql();
        }
    }
}
